/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 * Date:             2013.09.30                                          *
 *                                                                       *
 *************************************************************************/

//declaration header
#include "COMMON/info/MeshInfo.h"

//COMMON headers
#include "COMMON/info/InfoManager.h"
#include "COMMON/info/StructuredMeshInfo.h"
#include "COMMON/info/UnstructuredMeshInfo.h"
#include "COMMON/tbox/LogMessage.h"

#include <iostream>


namespace FreeMAPs
{

MeshInfo::MeshInfo(
    const std::string& object_name):
    Parent ("base_information", object_name),
    d_mesh_type (MeshType::UNSTRUCTURED_MESH),
    d_structured_mesh_info (NULL),
    d_unstructured_mesh_info (NULL)    
{
    create_objects();
}



void
MeshInfo::create_objects ()
{
    d_structured_mesh_info = new StructuredMeshInfo (this->get_full_name(), "structured_mesh_info");
    d_unstructured_mesh_info = new UnstructuredMeshInfo (this->get_full_name(), "unstructured_mesh_info");
}



MeshInfo::~MeshInfo()
{
    this->clear();
}



void
MeshInfo::clear()
{
    Utilities::clear_pointer_object (d_structured_mesh_info);
    Utilities::clear_pointer_object (d_unstructured_mesh_info);
}



void
MeshInfo::check_structured_mesh_is_used (
    const InputDatabase* db,
    const std::string& key) const
{
    if (!this->use_structured_mesh())
    {
        LogMessage::unknown_error (
            db,
            key,
            "it is used in structured mesh");
    }
}


const std::string
MeshInfo::get_mesh_file_location() const
{
    std::string file_location;
    if (this->use_unstructured_mesh())
    {
        file_location = d_unstructured_mesh_info->get_mesh_file_location();
//        std::cout << __FILE__ << __LINE__ << " file_location = " << file_location << std::endl;
    }
    else
    {
        //TODO
    }

    return file_location;
}



bool
MeshInfo::check_all_info_db (
        const InputDatabase* db)
{
    //mesh_type
    if( !db->key_exists("mesh_type") )
    {
        FREEMAPS_ERROR("in \"mesh_info\", can not find  \"mesh_type\" \n");
        return false;
    }
    if( !db->is_string("mesh_type") )
    {
        FREEMAPS_ERROR("in \"mesh_info\", \"mesh_type\" should be string \n");
        return false;
    }

    if( db->get_enum_with_default ("mesh_type", d_mesh_type) == MeshType::UNSTRUCTURED_MESH)
    {
        //unstructured_mesh_info
        if( db->key_exists("unstructured_mesh_info") )
        {
            bool check_ok = d_unstructured_mesh_info->check_all_info_db(db->get_database("unstructured_mesh_info"));
            if( !check_ok )
            {
                return false;
            }
        }
        else
        {
            FREEMAPS_ERROR("in \"mesh_info\", can not find  \"unstructured_mesh_info\" \n");
            return false;
        }
    }
    else
    {
        //other type
        //TODO
    }

    return true;
}



void
MeshInfo::get_from_input (
        const InputDatabase* db)
{
    this->prepare_for_use (db);

    db->insert_allowable_key ("mesh_type");
    db->insert_allowable_key ("structured_mesh_info");
    db->insert_allowable_key ("unstructured_mesh_info");
    db->check_allowable_keys ();

    /*
     * build mesh_type
     */
    {
        if (db->key_exists ("mesh_type") && db->is_string("mesh_type"))
        {
            db->check_requisite_key ("mesh_type", DataType::STRING, false, false);
            d_mesh_type = db->get_enum_with_default ("mesh_type", d_mesh_type);

            if (!this->use_structured_mesh())
            {
                db->check_disallowable_key (
                    "structured_mesh_info",
                    "when mesh_type is UNSTRUCTURED_MESH, use the key of \"unstructured_mesh_info\" to set mesh info");
            }

            if (!this->use_unstructured_mesh())
            {
                db->check_disallowable_key (
                    "unstructured_mesh_info",
                    "when mesh_type is STRUCTURED_MESH, use the key of \"structured_mesh_info\" to set mesh info");
            }
        }
    }

    if (this->use_structured_mesh())
    {
        if (db->key_exists ("structured_mesh_info") && db->is_database("structured_mesh_info"))
        {
            db->check_requisite_database ("structured_mesh_info");
            d_structured_mesh_info->get_from_input (db->get_database ("structured_mesh_info"));
        }
    }

    if (this->use_unstructured_mesh())
    {
        if (db->key_exists ("unstructured_mesh_info") && db->is_database("unstructured_mesh_info"))
        {
            db->check_requisite_key ("unstructured_mesh_info", DataType::DATABASE, false, false);
            d_unstructured_mesh_info->get_from_input (db->get_database ("unstructured_mesh_info"));
        }
    }
}



std::ostream&
operator << (
    std::ostream& os,
    const MeshInfo& rhs)
{
    os << "mesh_info" << RTN_FLAG;
    os << "{"  << RTN_FLAG;
    os << LogMessage::get_prefix (ONE_TAB) << "mesh_type = \"" << Utilities::enum_to_string (rhs.d_mesh_type) << "\"" << RTN_FLAG << RTN_FLAG;
    if (rhs.use_structured_mesh())
    {
        FREEMAPS_ASSERT_VALID_POINTER (rhs.d_structured_mesh_info);
        std::ostringstream oss;
        oss << *rhs.d_structured_mesh_info;
        os << LogMessage::get_log_info (oss, ONE_TAB)  << RTN_FLAG;
    }

    if (rhs.use_unstructured_mesh())
    {
        FREEMAPS_ASSERT_VALID_POINTER (rhs.d_unstructured_mesh_info);
        std::ostringstream oss;
        oss << *rhs.d_unstructured_mesh_info;
        os << LogMessage::get_log_info (oss, ONE_TAB)  << RTN_FLAG;
    }

    os << "}";

    return os;
}

} //namespace FreeMAPs
